﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace Snowdreamist.Windows.Navigation.Primitives
{
    public class NavigateProcessor
    {
        internal NavigateProcessor(
            NavigationHandlerRepository repository,
            NavigationHandlerSelector selector,
            NavigationHandlerInvoker invoker,
            NavigationSwitcher switcher,
            Session session
            )
        {
            this.Repository = repository;
            this.Selector = selector;
            this.Invoker = invoker;
            this.Switcher = switcher;
            this.Session = session;
        }

        public NavigationHandlerRepository Repository { get; set; }

        public NavigationHandlerSelector Selector { get; set; }

        public NavigationHandlerInvoker Invoker { get; set; }

        public NavigationSwitcher Switcher { get; set; }

        public Session Session { get; set; }

        public bool IsAutoActive { get; set; }

        public Uri RequestUri { get; set; }

        public object ViewModel { get; set; }

        public object View { get; set; }

        public NavigationContext GetContext(Exception error = null)
        {
            return new NavigationContext(this, this.RequestUri, this.ViewModel, this.View, this.Session, error);
        }

        public bool Process()
        {
            if (Interlocked.CompareExchange(ref this._isStarted, 1, 0) == 0)
            {
                // process
                if (this.View != null)
                {
                    // finish
                    this.Switcher.Switch(this.Session, null, this.View);
                    return true;
                }
                else if (this.ViewModel != null)
                {
                    // active
                    this.View = this.Invoker.ActiveView(this.ViewModel);
                    this.Switcher.Switch(this.Session, this.ViewModel, this.View);
                    return true;
                }
                else if (this.RequestUri != null)
                {
                    var handler = this.Selector.Select(this.RequestUri);

                    if (handler == null)
                        throw new HandlerNotFoundException();

                    using (var context = this.GetContext())
                    {
                        this.Invoker.Invoke(handler, context);
                    }

                    // switch
                    this.Switcher.Switch(this.Session, this.ViewModel, this.View);

                    return true;
                }
                else
                {
                    return false;
                }
            }
            else
            {
                throw new InvalidOperationException("Processor has already started");
            }
        }

        private int _isStarted = 0;
    }
}